package com.jsbs.iam.user.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jsbs.iam.common.core.dto.Result;
import com.jsbs.iam.common.core.utils.Json;
import com.jsbs.iam.common.core.utils.PageHelperTool;
import com.jsbs.iam.user.constant.RedisConstants;
import com.jsbs.iam.user.dto.*;
import com.jsbs.iam.user.entity.IamOrgFramework;
import com.jsbs.iam.user.entity.IamOrgTypeExtendedField;
import com.jsbs.iam.user.entity.IamOrganizationTypeBase;
import com.jsbs.iam.user.feign.ApplySystemFeign;
import com.jsbs.iam.user.mapper.OrgTypeMapper;
import com.jsbs.iam.user.service.OrgTypeService;
import com.jsbs.iam.user.vo.OrgTypeFieldInfoVo;
import io.netty.util.internal.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 * @BelongsProject: iam
 * @BelongsPackage: com.jsbs.iam.user.service.impl
 * @Author: WangJiYuan
 * @Description: TODO
 * @Version: 2022-12-02  17:36
 */
@Service
public class OrgTypeServiceImpl implements OrgTypeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(OrgTypeServiceImpl.class);

    @Autowired
    private OrgTypeMapper orgTypeMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ApplySystemFeign applySystemFeign;

    @Resource
    private RedissonClient redissonClient;

    private static final String ADMIN_USER = "admin";

    @Override
    public void addOrgType(OrgTypeAddDto orgTypeAddDto) {
        orgTypeAddDto.setOrgTypeCode(this.getIdByRedis("zzlx",6,"orgTypeCode",orgTypeAddDto.getCompanyCode()));
        orgTypeMapper.addOrgType(orgTypeAddDto);
    }

    @Override
    public int selectOrgCount(String orgTypeCode, String companyCode) {
        return orgTypeMapper.selectOrgCount(orgTypeCode,companyCode);
    }

    @Override
    public int selectOrgUserCount(String orgTypeCode, String companyCode) {
        return orgTypeMapper.selectOrgUserCount(orgTypeCode,companyCode);
    }

    @Override
    public List<IamOrgFramework> selectOrgInfo(String orgTypeCode, String companyCode) {
        return orgTypeMapper.selectOrgInfo(orgTypeCode,companyCode);
    }

    @Override
    @Transactional
    public void addOrgTypeField(OrgTypeFieldAddDto orgTypeFieldAddDto) {
        //从Redis中获取自增序列
        String fieldId = this.getIdByRedis("zdbm", 6,"fieldCode", orgTypeFieldAddDto.getCompanyCode());
        orgTypeFieldAddDto.setFieldId(fieldId);
        orgTypeMapper.addOrgTypeField(orgTypeFieldAddDto);
    }


    @Override
    public void updateOrgTypeField(OrgTypeFieldUpdateDto orgTypeFieldUpdateDto) {
        orgTypeMapper.updateOrgTypeField(orgTypeFieldUpdateDto);
    }

    @Override
    @Transactional
    public void deleteOrgTypeField(OrgTypeFieldUpdateDto orgTypeFieldUpdateDto) {
        if (orgTypeFieldUpdateDto.getFieldIds().size() > 0) {
            //根据字段id逻辑删除字段
            orgTypeMapper.deleteOrgTypeFieldById(orgTypeFieldUpdateDto);
            //根据id逻辑删除字段存储的数据
            orgTypeMapper.deleteOrgTypeFieldValueById(orgTypeFieldUpdateDto);
        }
    }

    @Override
    public PageInfo selectOrgTypeFieldList(OrgTypeFieldSelectDto orgTypeFieldSelectDto) {
        orgTypeFieldSelectDto.init();
        PageHelper.startPage(orgTypeFieldSelectDto.getCurrPage(), orgTypeFieldSelectDto.getPageSize());
        //查询对应组织类型下所有字段
        List<OrgTypeFieldInfoVo> list = orgTypeMapper.selectOrgTypeFieldList(orgTypeFieldSelectDto);
        PageInfo<OrgTypeFieldInfoVo> page = new PageInfo<>(list);
        PageInfo<OrgTypeFieldInfoVo> pageInfo =
                PageHelperTool.initPageInfoObj(orgTypeFieldSelectDto.getCurrPage(), (int) page.getTotal(), orgTypeFieldSelectDto.getPageSize(), page);
        return pageInfo;
    }

    @Override
    @Transactional
    public void copyOrgTypeField(OrgTypeFieldUpdateDto orgTypeFieldUpdateDto) {
        List<String> fieldIds = orgTypeFieldUpdateDto.getFieldIds();
        //将要复制到的主体字段数据
        List<IamOrgTypeExtendedField> listM = orgTypeMapper.selectFieldListByOrgTypeCode(orgTypeFieldUpdateDto);
        //用于复制的字段数据
        List<IamOrgTypeExtendedField> listC = orgTypeMapper.selectFieldListById(fieldIds,orgTypeFieldUpdateDto.getCompanyCode());
        //去除listC中已有字段剩下的字段数据
        List<IamOrgTypeExtendedField> list = new ArrayList<IamOrgTypeExtendedField>();
        if (listM != null && listM.size() > 0 && listC != null && listC.size() > 0) {
            //遍历用于复制的集合
            for (int i = 0; i < listC.size(); i++) {
                IamOrgTypeExtendedField orgTypeFieldC = listC.get(i);
                String fieldNameC = orgTypeFieldC.getFieldName();
                for (IamOrgTypeExtendedField orgTypeField : listM) {
                    String fieldName = orgTypeField.getFieldName();
                    if (StringUtils.equalsIgnoreCase(fieldNameC, fieldName)) {
                        //如果用于复制的集合中含有和目标集合相同元素则删除对应元素
                        listC.remove(i);
                    }
                }
            }
        }
        list = listC;

        if (list != null&& list.size() > 0) {
            for (IamOrgTypeExtendedField orgTypeField : list) {
                //重新获取id
                String id = this.getIdByRedis("zdbm", 6, "fieldCode", orgTypeFieldUpdateDto.getCompanyCode());
                orgTypeField.setFieldId(id);
                orgTypeField.setOrgTypeCode(orgTypeFieldUpdateDto.getOrgTypeCode());
                orgTypeField.setCompanyCode(orgTypeFieldUpdateDto.getCompanyCode());
                orgTypeField.setUpdatePerson(orgTypeFieldUpdateDto.getUpdatePerson());
            }
            //批量插入字段数据
            orgTypeMapper.insertFieldData(list);
        }
    }


    @Override
    public List<IamOrganizationTypeBase> getOrgTypeData(String companyCode, String userCode, String adminRoleCode) {
        List<IamOrganizationTypeBase> orgTypes = new ArrayList<IamOrganizationTypeBase>();
        //权限限制
        if (ADMIN_USER.equals(userCode)) {
            //超管
            orgTypes = orgTypeMapper.getOrgTypeData(companyCode);
        } else {
            //普管
            //获取普通管理员的组织类型数据
            orgTypes = orgTypeMapper.getAdminRoleOrgTypeData(adminRoleCode, companyCode);
        }
        return orgTypes;
    }

    /**
     * 系统自动生成编码
     * @param prefix  前缀
     * @param numLength   后面数字的位数
     * @param type   区分编码类型
     * @param companyCode  租户编码
     * @return
     */
    public String getIdByRedis(String prefix, int numLength, String type, String companyCode) {
        // 生成组织类型编码加锁，失效时间10分钟
        RLock lock = redissonClient.getLock(RedisConstants.ORG_TYPE_CODE_LOCK);
        String returnCode="";

        try {
            String upperCode ="";
            //Redis中存储的key
            String key = "orgType_" + prefix;
            Long size = redisTemplate.opsForList().size(key);//查找 prefix 的key值的数据长度
            if (size > 0) {//有数据
                List leve = redisTemplate.opsForList().range(key, 0, -1);//获取该key下面的所有值(-1 所有的值，；1下一个值
                upperCode = leve.get(leve.size() - 1).toString();//返回最后一个值
            }
            //判断redis中序列是否为空
            if (StringUtils.isEmpty(upperCode)) {
                if ("orgTypeCode".equals(type)) {
                    //查询组织类型编码
                    upperCode = orgTypeMapper.selectOrgTypeId(companyCode);
                } else if ("fieldCode".equals(type)) {
                    //查询组织类型拓展字段表对应字段编码
                    upperCode = orgTypeMapper.selectFieldCode(companyCode);
                }
            }
            int Suffix;  //后缀数字
            if (!StringUtil.isNullOrEmpty(upperCode)) { //有数据
                String sequence = upperCode.substring(prefix.length());//截取前缀开始的后面的数字
                Suffix = Integer.parseInt(sequence);
                Suffix++;//最后的序号加一
            } else {
                Suffix = 1;//没有数据
            }
            returnCode = prefix + String.format("%0" + numLength + "d", Suffix);//后缀不够numLength长，前面补充0
            redisTemplate.opsForList().rightPush(key, returnCode);//存入Redis

        } catch (Exception e) {
            LOGGER.error("Route=>OrgTypeServiceImpl method=>getIdByRedis 组织类型,系统自动生成编码失败:", e);
            throw new RuntimeException("组织类型,系统自动生成编码异常");
        } finally {
            // 手动解锁
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
        return  returnCode;
    }

    @Override
    @Transactional
    public void deleteOrgType(OrgTypeDeleteDto deleteDto) throws URISyntaxException {
        //删除组织类型基础数据
        orgTypeMapper.deleteOrgType(deleteDto);
        //根据组织类型获取组织数据
        List<IamOrgFramework> orgList = orgTypeMapper.selectOrgInfo(deleteDto.getOrgTypeCode(), deleteDto.getCompanyCode());
        if (orgList.size() > 0) {
            deleteDto.setOrgList(orgList);
            //逻辑删除组织数据
            orgTypeMapper.deleteSubOrg(deleteDto);
        }
        //删除字段数据
        orgTypeMapper.deleteOrgTypeFieldData(deleteDto);
        //删除字段保存的数据
        orgTypeMapper.deleteOrgTypeExtendData(deleteDto);

        //删除组织类型和角色之间的关系
        OrgTypeRelationDeleteDto relationDeleteDto = new OrgTypeRelationDeleteDto();
        //复制数据
        BeanUtils.copyProperties(deleteDto,relationDeleteDto);
        //远程调用auth服务,删除组织类型和角色之间的关系
        Result result = applySystemFeign.deleteOrgTypeRelation(relationDeleteDto);
        LOGGER.info("远程调用auth服务删除组织类型和角色之间的关系", Json.toJsonString(relationDeleteDto));
        if (!result.isSuccess()) {
            LOGGER.info("远程调用auth服务删除组织类型和角色之间的关系,失败!!!", Json.toJsonString(relationDeleteDto));
            throw new RuntimeException("远程调用auth服务删除组织类型和角色之间的关系失败!!!");
        }
    }

    @Override
    public int checkTypeName(String orgTypeName, String companyCode) {
        return orgTypeMapper.checkTypeName(orgTypeName,companyCode);
    }

    @Override
    public int checkTypeCode(String orgTypeCode, String companyCode) {
        return orgTypeMapper.checkTypeCode(orgTypeCode,companyCode);
    }
}
